/*
	gameinfo.cc		Game States
	Copyright (c) 2004, 2005, 2006 Kriang Lerdsuwanakij
	email:		lerdsuwa@users.sourceforge.net

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "config.h"

#include "gameinfo.h"
#include "game.h"

game_info::game_info()
{
	board_ptr = 0;
	game_play = false;
	use_clock = false;
}

game_info::~game_info()
{
	delete board_ptr;
}

void game_info::new_game_remaining(int queue_size)
{
			// player must be set before this
	set_game_play_from_board();

				// Update history for undo
	board_history[0] = *board_ptr;
	player_history[0] = player;
	num_history = 1;
	max_num_history = 1;
				// When move queue is used
	min_num_history = 1 + queue_size;
}

void game_info::set_game_play_from_board()
{
	game_play = board_ptr->can_play();
	if (!game_play)
		game_result = game_result_end;
}

void game_info::new_game_from_begin(int queue_size)
{
	random_game = false;
	first_play_is_pass = false;

	if (!board_ptr)
		board_ptr = new byte_board_info;

	*board_ptr = &board_begin;
	player = BLACK;

	new_game_remaining(queue_size);
}

void game_info::new_game_from_board(const byte_board_info *b, int p)
{
	random_game = true;
	random_game_pieces =  b->get_num_move() + 4;
	first_play_is_pass = false;

	if (!board_ptr)
		board_ptr = new byte_board_info;

	*board_ptr = *b;
	player = p;

					// First move is a pass
	if (!board_ptr->can_play(player)
	    && board_ptr->can_play(switch_color(player))) {
		player = switch_color(player);
		first_play_is_pass = true;
	}

	new_game_remaining(0);
}

bool game_info::is_undoable() const
{
	int	i = num_history;
	if (i <= min_num_history)	// Already at the beginning of the game
					// Use <= to support move queue
		return false;

	return true;
}

bool game_info::is_redoable() const
{
	int	i = num_history;
	if (i == max_num_history)	// Already at the end of the game
		return false;

	return true;
}

void game_info::undo()
{
	int	i = num_history;

				// Skip AI's turns
	while (i > min_num_history && is_computer_player(player_history[i-2]))
		i--;

	if (i > min_num_history)		// Undo human move
		i--;

	*board_ptr = board_history[i-1];

	player = player_history[i-1];
			// player must be set before this
	set_game_play_from_board();

	num_history = i;
}

void game_info::redo()
{
	int	i = num_history;

				// Skip AI's turns
	while (i < max_num_history && is_computer_player(player_history[i-1]))
		i++;

	if (i < max_num_history)		// Redo human move
		i++;

	if (redo_ai_move) {
				// Skip AI's turns
		while (i < max_num_history 
		       && is_computer_player(player_history[i-1]))
			i++;
	}

	*board_ptr = board_history[i-1];

	player = player_history[i-1];
			// player must be set before this
	set_game_play_from_board();

	num_history = i;
}

void game_info::place_piece(int pos, int time)
{
	if (use_clock &&
	    ((player == BLACK && time > clock_history_black[num_history-1])
	     || (player == WHITE && time > clock_history_white[num_history-1]))) {
		player_timeout();
		return;
	}

	board_ptr->place_piece(player, pos);

	int	old_player = player;

	if (board_ptr->can_play(switch_color(player))) {
		player = switch_color(player);
	}
	else if (!board_ptr->can_play(player)) {
		game_play = false;
		game_result = game_info::game_result_end;
	}

				// Update history for undo
	bool keep_history = false;
	board_history[num_history] = *board_ptr;
				// Repeat same move
	if (num_history < max_num_history 
	    && move_history[num_history-1] == pos)
		keep_history = true;

	move_history[num_history-1] = pos;
	time_history[num_history-1] = time;
	if (use_clock) {
		if (old_player == BLACK) {
			clock_history_black[num_history] = clock_history_black[num_history-1] - time;
			clock_history_white[num_history] = clock_history_white[num_history-1];
		}
		else {
			clock_history_black[num_history] = clock_history_black[num_history-1];
			clock_history_white[num_history] = clock_history_white[num_history-1] - time;
		}
	}

				// Next move
	player_history[num_history] = player;
	num_history++;
				// Remove redo capability
	if (!keep_history)
		max_num_history = num_history;
}

void game_info::player_timeout()
{
	game_play = false;
	if (player == BLACK)
		game_result = game_result_timeout_black;
	else
		game_result = game_result_timeout_white;
}

void game_info::player_resign()
{
	game_play = false;
	if (player == BLACK)
		game_result = game_result_resign_black;
	else
		game_result = game_result_resign_white;
}

void game_info::game_end()
{
	game_play = false;
	game_result = game_result_end;
}

int game_info::get_clock()
{
	if (player == BLACK)
		return clock_history_black[num_history-1];
	else
		return clock_history_white[num_history-1];
}
